home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1995 October
/
EnigmA AMIGA RUN 01 (1995)(G.R. Edizioni)(IT)[!][issue 1995-10][Aminet 7].iso
/
Aminet
/
misc
/
emu
/
FrodoV1_5.lha
/
src
/
6510.asm
< prev
next >
Wrap
Assembly Source File
|
1995-06-04
|
57KB
|
3,131 lines
*
* 6510.asm - 6510-Emulation (eigener Task)
*
* Copyright (C) 1994-1995 by Christian Bauer
*
*
* Anmerkungen:
* ------------
*
* Register d0/d1 - WICHTIG:
* - Der Emulator geht davon aus, daß die MSWs von d0 und d1 immer Null
* sind. Denn dadurch kann das C64-RAM mittels (RAMPTR,d0.l) ohne
* Vorzeichen indiziert angesprochen werden.
* - Die Makros Read#?Zero#? und Read#?Ind#? gehen zusätlich davon aus,
* daß nur das untere Byte von d0 Null ist, da diese Makros immer nur
* am Anfang eines Befehls stehen und d0 vom Next-Makro noch gelöscht
* ist
*
* Speicherkonfigurationen:
*
* $01 $a000-$bfff $d000-$dfff $e000-$ffff
* -----------------------------------------------
* 0 RAM RAM RAM
* 1 RAM Char-ROM RAM
* 2 RAM Char-ROM Kernal-ROM
* 3 Basic-ROM Char-ROM Kernal-ROM
* 4 RAM RAM RAM
* 5 RAM I/O RAM
* 6 RAM I/O Kernal-ROM
* 7 Basic-ROM I/O Kernal-ROM
*
* Zugriff auf den C64-Speicher:
* - Fast alle Speicherzugriffe laufen über die ReadByte/WriteByte-Makros,
* die die eingestellte Speicherkonfiguration dadurch berücksichtigen,
* daß die oberen 8 Adreßbits als Index in eine Sprungtabelle
* (ReadTab/WriteTab) dienen, die Zeiger auf die ReadByte*/WriteByte*-
* Routinen enthalten, über die der tatsächliche Zugriff erfolgt.
* Für jede der 8 Speicherkonfigurationen existiert jeweils eine solche
* Tabelle Bei einer Änderung der Speicherkonfiguration (NewConfig)
* werden die Zeiger auf die Tabellen (RDTAB/WRTAB) geändert.
* - Das LESEN aus der Zero-Page geschieht immer direkt,
* da dort keine Register liegen ($01 wird auch im RAM abgelegt)
* - Beim Schreiben in die Zero-Page wird nur auf $00/$01 getestet,
* ansonsten direkt zugegriffen
* - Der Stack wird immer direkt angesprochen
* - Die ReadByte-Routinen dürfen nur d0-d1/a0 verändern.
* a1 enthält die Rücksprungadresse, die Routinen müssen also mit
* "jmp (a1)" enden.
* - Die WriteByte-Routinen dürfen nur d0-d1/a0-a1 verändern
*
* Programmzähler:
* - Aus Geschwindigkeitsgründen wird der PC durch einen 32-Bit-
* Amiga-Zeiger repräsentiert und über diesen direkt auf den
* Speicher zugegriffen (und nicht über ReadByte). Bei einem
* Sprungbefehl wird aus dem 16-Bit Sprungziel und der aktuellen
* Speicherkonfiguration die neue 32-Bit-Adresse berechnet,
* indem ähnlich zur ReadTab die oberen 8 Bit des Sprungziels
* als Index in die JumpTab verwendet werden. Die darüber aufgerufenen
* Routinen führen die Umrechnung durch.
* - Durch die Art, wie das Hauptprogramm den Speicher anfordert,
* entsprechen die unteren 16 Bit des 32-Bit-PCs immer der
* 16-Bit-C64-Adresse. Das erleichtert erheblich das Ablegen des
* PC auf dem Stack, da dazu einfach nur die unteren 16 Bit
* genommen werden müssen (ansonsten müßte man je nach RAM/ROM-
* Bereich erst die jeweilige Basisadresse subtrahieren).
* - Im RAM-Bereich $10000-$100ff wird der Opcode $d2 installiert,
* der den PC auf $0000-$00ff umrechnet, falls ein Programm den
* Wraparound macht
* - Durch diese Art der PC-Verwaltung bestehen folgende Inkompatibilitäten:
* - Ein Branch oder ein Hineinlaufen in einen anderen Speicherbereich
* (z.B. RAM->ROM) funktioniert nicht. Das sollte allerdings kein
* Problem darstellen.
* - Ein Sprung in den I/O-Bereich ist z.Z. nicht möglich
*
* Condition-Codes:
* - Die Emulation verwendet zwei Register, um die Prozessorflags zu
* speichern: RCCR und RP.
* - RCCR ist ein Abbild des 680x0-CCR und wird nach den entsprechenden
* Operationen mit "move ccr,RCCR" gelesen. Von RCCR werden nur das N-
* und das Z-Flag verwendet.
* - Die einzigen Opcodes, die V ändern, sind ADC, SBC, CLV, PLP und RTI.
* Darum wird das V-Flag nicht aus dem 680x0-V-Flag erzeugt, sondern
* gegebenenfalls von Hand gesetzt.
* - Im oberen Byte (Bit 8-15) von RP sind die 6510-Flags V,B,D und I
* in der selben Anordnung wie beim 6510 gespeichert. Das untere Byte
* enthält in Bit 0 das Carry-Flag in 6510-Interpretation (bei SBC und
* CMP/CPX/CPY inverse Bedeutung zum 680x0), das bei den entsprechenden
* Opcodes aus dem CCR gelesen (und ggf. invertiert) wird. Der Einfachheit
* halber wird immer das ganze untere Byte von CCR gelesen, da nur Bit 0
* interessant ist.
*
* Opcode-Ausführung:
* - Es gibt keine Fetch-Decode-Schleife, sondern jede Opcode-Routine
* enthält am Schluß den Code, der den nächsten Befehl ausführt
* ("Next"-Makro).
* - Die Verzweigung in die einzelnen Opcode-Routinen geschieht über
* eine Sprungtabelle, die OpcodeTable. Das Register OPTABPTR enthält
* einen Zeiger auf diese Tabelle (vor der Tabelle steht noch der
* Zyklenzähler, auf den so schneller zugegriffen werden kann).
*
* Zyklenzähler/Periodic/Interrupts:
* - Die Variable CyclesLeft (erreichbar über (OPTABPTR)) enthält die
* Anzahl Zyklen, die dem 6510 in der augenblicklichen Rasterzeile noch
* zur Verfügung stehen
* - Nach jeder Opcode-Ausführung wird dieser Zähler um die Zyklenzahl
* des gerade ausgeführten Befehls erniedrigt. Dazu wird dem Next-Makro
* die Anzahl Zyklen übergeben. Unterschreitet der Zähler Null, wird
* die Routine "Periodic" aufgerufen.
* - In dieser Routine werden die Unterroutinen von VIC und CIA
* ausgeführt, die die Aktionen für eine Rasterzeile durchführen
* (VIC (Periodic6569): Eine Bildschirmzeile aufbauen, CIA
* (Periodic6526): Timer zählen)
* - In Periodic6569 wird der Zyklenzähler neu gesetzt (der Wert hängt
* davon ab, ob eine Bad Line stattfand oder nicht)
*
* Interrupts:
* - Die Haupt-Interruptquellen sind VIC und CIA, daher prüft der
* Emulator das Auftreten eines Interrupts im Rahmen der Periodic-
* Routine
* - Es gibt folgende Interrupt-Möglichkeiten (Prioritäten):
* - RESET, Sprung nach ($FFFC) oder 6510-Task beenden (RESETIsEXIT-Flag)
* - NMI, Sprung nach ($FFFA)
* - VIC-IRQ, I-Flag wird geprüft, Sprung nach ($FFFE)
* - CIA-IRQ, I-Flag wird geprüft, Sprung nach ($FFFE)
* - Die Aufteilung in VIC- und CIA-IRQ erleichtert die Handhabung, wenn
* beide IRQs gleichzeitig auftreten
* - Die einzige Möglichkeit, außerhalb des Periodic einen Interrupt
* auszulösen, ist das Löschen des I-Flags, wenn ein IRQ ansteht.
* Die Opcode-Routinen für PLP, RTI und CLI enthalten deswegen besondere
* Abfragen, die ggf. in den Interrupt-Handler verzweigen.
*
* Erweiterungen:
* - Über den Opcode $f2 sind die 1541-Routinen implementiert. Dem Opcode
* folgt ein Byte, das die Nummer der auzurufenden Routine angibt.
*
* Inkompatibilitäten:
* - ($ff),Y-Adressierung liest das zweite Byte der indirekten Adresse
* aus $0100 statt $0000. Dies geschieht aus Geschwindigkeitsgründen,
* der korrekte Code ist im Makro ReadAdrIndY auskommentiert.
* - In der Verwaltung des PCs bestehen einige Ungenauigkeiten (siehe
* Abschnitt "Programmzähler")
* - RMW-Befehle sollten erst die Originaldaten und dann die geänderten
* schreiben, aber das spielt nur eine Rolle für Register wie das
* VIC-IRQFLAG-Register, das in 6569.asm deswegen speziell behandelt wird
* - Zyklen werden nur für ganze Befehle gezählt, Extra-Zyklen für
* Seitenüberschreitungen werden nicht berechnet (dies betrifft die
* Adressierungsarten xxxx,X xxxx,Y (xx),Y und die Branch-Befehle)
* - ADC und SBC im Dezimalmodus setzen die Flags nicht korrekt
* - RRA und ISB berücksichtigen das D-Flag nicht
*
MACHINE 68020
INCLUDE "exec/types.i"
INCLUDE "exec/macros.i"
INCLUDE "exec/execbase.i"
INCLUDE "exec/nodes.i"
INCLUDE "dos/dos.i"
INCLUDE "dos/dostags.i"
INCLUDE "Frodo_rev.i"
CATCOMP_NUMBERS = 1
INCLUDE "Strings.i"
XREF _SysBase
XREF _DOSBase
XREF _IntuitionBase
XREF GetString ;Strings.o
XREF TheLocale
XDEF TheRAM ;Main.asm
XDEF TheBasic
XDEF TheKernal
XDEF TheChar
XDEF TheColor
XREF MainTask
XREF Random
XREF ReadFrom6526A ;6526.asm
XREF ReadFrom6526B
XREF WriteTo6526A
XREF WriteTo6526B
XREF Reset6526
XREF Init6569 ;6569.asm
XREF Exit6569
XREF ReadFrom6569
XREF WriteTo6569
XREF Periodic6569
XREF AmigaToFront
XREF EmulToFront
XREF ReadFrom6581 ;6581.asm
XREF WriteTo6581
XREF Reset6581
XREF IECOut ;1541.asm
XREF IECOutATN
XREF IECOutSec
XREF IECIn
XREF IECSetATN
XREF IECRelATN
XREF IECTurnaround
XREF IECRelease
XDEF Init6510
XDEF Start6510
XDEF Stop6510
XDEF Pause6510
XDEF Resume6510
XDEF Localize6510
XDEF IntIsRESET
XDEF IntIsNMI
XDEF IntIsVICIRQ
XDEF IntIsCIAIRQ
XDEF CyclesLeft
XDEF CPUTask
XDEF Peri6569Cont
XDEF Peri6526Cont
SECTION "CODE",CODE
**
** Definitionen
**
; Bitdefinitionen für RP (6510-Statusregister)
CarryBit = 0 ;Carry (nach 6510-Definition)
InterruptBit = 10 ;Interrupts abgeschaltet
InterruptMask = $0400
DecimalBit = 11 ;Dezimalmodus
DecimalMask = $0800
BreakBit = 12 ;Break-Befehl (nur auf dem Stack)
BreakMask = $1000
OverflowBit = 14 ;Arith. Überlauf
OverflowMask = $4000
; Registerbelegung (Achtung: In 1541.asm sind ebenfalls solche
; Definitionen, die hiermit übereinstimmen müssen!)
RA EQUR d2 ;A
RX EQUR d3 ;X
RY EQUR d4 ;Y
RS EQUR d5 ;S (16-Bit, $01xx)
RCCR EQUR d6 ;CCR, nur N und Z
RP EQUR d7 ;Oberes Byte: 6510-Status ohne N,Z und C.
;Bit #0: Carry
RDTAB EQUR a2 ;Zeiger auf ReadByte-Sprungtabelle
WRTAB EQUR a3 ;Zeiger auf WriteByte-Sprungtabelle
;256*8*4+WRTAB zeigt auf JumpTab
RAMPTR EQUR a4 ;Zeiger auf C64-RAM
RPC EQUR a5 ;PC (32-Bit Amiga-Adresse, untere 16 Bit
; stimmen mit C64-PC überein)
OPTABPTR EQUR a6 ;Zeiger auf die Opcode-Dispatch-Tabelle
; und den Zyklenzähler
*
* Makros für Speicherzugriffe und Adreßberechnungen
*
; Ein C64-Byte lesen
; -> d0.w: Adresse
; <- d0.b: Byte
ReadByte MACRO
cmp.w #$a000,d0 ;Unterhalb von $a000 ist nur Speicher
blo \@1$
move.w d0,d1
lsr.w #8,d1
lea \@2$(pc),a1 ;Ist hier schneller, weil sonst
move.l (RDTAB,d1.w*4),a0 ;hinter dem jmp (a0) ein bra \@2$
jmp (a0) ;stehen müßte
\@1$ move.b (RAMPTR,d0.l),d0
\@2$
ENDM
; Ein C64-Wort lesen (Als Makro schneller)
; -> d0.w: Adresse
; <- d0.w: Wort (Bytefolge korrigiert)
ReadWord MACRO
move.l d0,-(sp) ;Adresse merken
ReadByte
move.b d0,d1
move.l (sp)+,d0 ;Adresse zurückholen
addq.w #1,d0 ;Nächstes Byte
move.l d1,-(sp) ;Lo-Byte merken
ReadByte
lsl.w #8,d0 ;Hi-Byte richtig schieben
move.l (sp)+,d1
move.b d1,d0 ;Lo-Byte dazunehmen
ENDM
; Ein C64-Byte schreiben
; -> d0.w: Adresse (16 bit)
; -> d1.b: Byte
; Adresse steht dann in a1
WriteByte MACRO
cmp.w #$a000,d0
blo \@1$
move.l d0,a1
lsr.w #8,d0
move.l (WRTAB,d0.w*4),a0
jsr (a0)
bra \@2$
\@1$ move.b d1,(RAMPTR,d0.l)
cmp.b #2,d0
bhs \@2$
NewConfig
\@2$
ENDM
; Ein C64-Wort am PC lesen und PC erhöhen
ReadPCWord MACRO
move.w (RPC)+,d0
rol.w #8,d0
ENDM
; Relative Adressierung
ReadByteRel MACRO
move.b (RPC)+,d0
ext.w d0
ENDM
; Absolute Adressierung
ReadAdrAbs MACRO
ReadPCWord
ENDM
ReadByteAbs MACRO
ReadAdrAbs
ReadByte
ENDM
; Indirekte Adressierung
ReadAdrInd MACRO
ReadPCWord
move.l d0,-(sp) ;Adresse merken
ReadByte
move.b d0,d1
move.l (sp)+,d0 ;Adresse zurückholen
addq.b #1,d0 ;Nächstes Byte OHNE Page-Crossing
move.l d1,-(sp) ;Lo-Byte merken
ReadByte
lsl.w #8,d0 ;Hi-Byte richtig schieben
move.l (sp)+,d1
move.b d1,d0 ;Lo-Byte dazunehmen
ENDM
; Zero-Page Adressierung
ReadAdrZero MACRO
move.b (RPC)+,d0
ENDM
ReadByteZero MACRO ;Register
ReadAdrZero
move.b (RAMPTR,d0.w),\1
ENDM
; Absolut,X
ReadAdrAbsX MACRO
ReadPCWord
add.w RX,d0
ENDM
ReadByteAbsX MACRO
ReadAdrAbsX
ReadByte
ENDM
; Absolut,Y
ReadAdrAbsY MACRO
ReadPCWord
add.w RY,d0
ENDM
ReadByteAbsY MACRO
ReadAdrAbsY
ReadByte
ENDM
; Zero-Page,X
ReadAdrZeroX MACRO
move.b (RPC)+,d0
add.b RX,d0
ENDM
ReadByteZeroX MACRO ;Register
ReadAdrZeroX
move.b (RAMPTR,d0.w),\1
ENDM
; Zero-Page,Y
ReadAdrZeroY MACRO
move.b (RPC)+,d0
add.b RY,d0
ENDM
ReadByteZeroY MACRO ;Register
ReadAdrZeroY
move.b (RAMPTR,d0.w),\1
ENDM
; (Ind,X)
ReadAdrIndX MACRO
move.b (RPC)+,d0
add.b RX,d0
move.b (RAMPTR,d0.w),d1 ;LSB lesen
addq.b #1,d0
move.b (RAMPTR,d0.w),d0 ;MSB lesen
lsl.w #8,d0
move.b d1,d0 ;LSB einfügen
ENDM
ReadByteIndX MACRO
ReadAdrIndX
ReadByte
ENDM
; (Ind),Y
ReadAdrIndY MACRO
move.b (RPC)+,d0
;(Korrekt) move.b (RAMPTR,d0.w),d1 ;LSB lesen
; addq.b #1,d0
; move.b (RAMPTR,d0.w),d0 ;MSB lesen
; lsl.w #8,d0
; move.b d1,d0 ;LSB einfügen
move.w (RAMPTR,d0.w),d0 ;(Abgekürzt)
rol.w #8,d0 ;Geht bei ($ff),y schief
add.w RY,d0
ENDM
ReadByteIndY MACRO
ReadAdrIndY
ReadByte
ENDM
; Ein Byte (Arg1) auf den Stapel schieben
PushByte MACRO ;Register
move.b \1,(RAMPTR,RS.w)
subq.b #1,RS
ENDM
; PC auf Stack schieben
PushPC MACRO
move.w RPC,d0
move.w d0,d1
lsr.w #8,d0
PushByte d0
PushByte d1
ENDM
; PC+1 auf den Stack schieben
PushPCPlus1 MACRO
move.w RPC,d0
addq.w #1,d0
move.w d0,d1
lsr.w #8,d0
PushByte d0
PushByte d1
ENDM
; Status auf Stack schieben
PushP MACRO
move.w RP,d0 ;6510-Status holen
lsr.w #8,d0
and.b #$5c,d0 ;V,B,D,I behalten
or.b #$20,d0 ;1-Bit setzen
btst #CarryBit,RP ;C dazunehmen
beq \@1$
or.b #$01,d0
\@1$ btst #3,RCCR ;N dazunehmen
beq \@2$
or.b #$80,d0
\@2$ btst #2,RCCR ;Z dazunehmen
beq \@3$
or.b #$02,d0
\@3$ PushByte d0
ENDM
; Ein Byte vom Stapel nach Arg1 lesen
PopByte MACRO ;Register
addq.b #1,RS
move.b (RAMPTR,RS.w),\1
ENDM
; Status vom Stack holen
PopP MACRO
PopByte d0
move ccr,RCCR
and.b #$08,RCCR ;N holen
move.b d0,RP
and.b #$4c,RP ;V,D,I behalten
lsl.w #8,RP
btst #1,d0 ;Z holen
beq \@1$
or.b #$04,RCCR
\@1$ btst #0,d0 ;C holen
beq \@2$
or.b #$01,RP
\@2$
ENDM
; PC setzen
; -> d0.w: 16-Bit-Adresse
; <- RPC.l: Amiga-Adresse
Jump MACRO
move.w d0,d1
lsr.w #8,d1
move.l 256*8*4(WRTAB,d1.w*4),a0
jsr (a0)
ENDM
; Nächsten Befehl ausführen
Next MACRO ;Zyklenzahl
IFNE \1
subq.w #\1,(OPTABPTR) ;Anzahl Zyklen abziehen
bmi Periodic ;Alle verbraucht: Periodic
ENDC
moveq #0,d0
move.b (RPC)+,d0 ;Opcode lesen
move.l 4(OPTABPTR,d0.w*4),a0 ;Zeiger auf die Opcode-Routine holen
jmp (a0) ;Routine aufrufen
ENDM
; Speicherkonfiguration anpassen
NewConfig MACRO
move.b 1(RAMPTR),d0 ;Config lesen
and.w #7,d0 ;Relevante Bits maskieren
movem.l (ConfigTab,pc,d0.w*8),RDTAB/WRTAB
ENDM
; Ein C64-Byte in die Zero-Page schreiben und nächsten Befehl ausführen.
; Prüfen, ob sich die Speicherkonfiguration geändert hat.
; -> d0.w: Adresse (16 bit)
; -> Arg1: Byte
WriteZeroNext MACRO ;Register, Zyklenzahl
move.b \1,(RAMPTR,d0.w)
cmp.b #2,d0
bhs \@1$
NewConfig
\@1$ Next \2
ENDM
**
** Emulation vorbereiten (Sprungtabellen aufbauen)
**
; ReadTabs aufbauen
Init6510 lea ReadTab0,a0 ;Alle mit RAM vorbelegen
move.w #256*8-1,d0
1$ move.l #ReadByteRAM,(a0)+
dbra d0,1$
lea ReadTab3+160*4,a0 ;Basic-ROM
moveq #31,d0
21$ move.l #ReadByteBasic,(a0)+
dbra d0,21$
lea ReadTab7+160*4,a0
moveq #31,d0
22$ move.l #ReadByteBasic,(a0)+
dbra d0,22$
lea ReadTab2+224*4,a0 ;Kernal-ROM
moveq #31,d0
31$ move.l #ReadByteKernal,(a0)+
dbra d0,31$
lea ReadTab3+224*4,a0
moveq #31,d0
32$ move.l #ReadByteKernal,(a0)+
dbra d0,32$
lea ReadTab6+224*4,a0
moveq #31,d0
33$ move.l #ReadByteKernal,(a0)+
dbra d0,33$
lea ReadTab7+224*4,a0
moveq #31,d0
34$ move.l #ReadByteKernal,(a0)+
dbra d0,34$
lea ReadTab5+208*4,a0 ;I/O-Bereich
move.l #ReadByteVIC,(a0)+
move.l #ReadByteVIC,(a0)+
move.l #ReadByteVIC,(a0)+
move.l #ReadByteVIC,(a0)+
move.l #ReadByteSID,(a0)+
move.l #ReadByteSID,(a0)+
move.l #ReadByteSID,(a0)+
move.l #ReadByteSID,(a0)+
move.l #ReadByteColor,(a0)+
move.l #ReadByteColor,(a0)+
move.l #ReadByteColor,(a0)+
move.l #ReadByteColor,(a0)+
move.l #ReadByteCIA1,(a0)+
move.l #ReadByteCIA2,(a0)+
move.l #ReadByteUndef,(a0)+
move.l #ReadByteUndef,(a0)
lea ReadTab6+208*4,a0
move.l #ReadByteVIC,(a0)+
move.l #ReadByteVIC,(a0)+
move.l #ReadByteVIC,(a0)+
move.l #ReadByteVIC,(a0)+
move.l #ReadByteSID,(a0)+
move.l #ReadByteSID,(a0)+
move.l #ReadByteSID,(a0)+
move.l #ReadByteSID,(a0)+
move.l #ReadByteColor,(a0)+
move.l #ReadByteColor,(a0)+
move.l #ReadByteColor,(a0)+
move.l #ReadByteColor,(a0)+
move.l #ReadByteCIA1,(a0)+
move.l #ReadByteCIA2,(a0)+
move.l #ReadByteUndef,(a0)+
move.l #ReadByteUndef,(a0)
lea ReadTab7+208*4,a0
move.l #ReadByteVIC,(a0)+
move.l #ReadByteVIC,(a0)+
move.l #ReadByteVIC,(a0)+
move.l #ReadByteVIC,(a0)+
move.l #ReadByteSID,(a0)+
move.l #ReadByteSID,(a0)+
move.l #ReadByteSID,(a0)+
move.l #ReadByteSID,(a0)+
move.l #ReadByteColor,(a0)+
move.l #ReadByteColor,(a0)+
move.l #ReadByteColor,(a0)+
move.l #ReadByteColor,(a0)+
move.l #ReadByteCIA1,(a0)+
move.l #ReadByteCIA2,(a0)+
move.l #ReadByteUndef,(a0)+
move.l #ReadByteUndef,(a0)
lea ReadTab1+208*4,a0 ;Char-ROM
moveq #15,d0
41$ move.l #ReadByteChar,(a0)+
dbra d0,41$
lea ReadTab2+208*4,a0
moveq #15,d0
42$ move.l #ReadByteChar,(a0)+
dbra d0,42$
lea ReadTab3+208*4,a0
moveq #15,d0
43$ move.l #ReadByteChar,(a0)+
dbra d0,43$
; WriteTabs aufbauen
lea WriteTab0,a0 ;Alle mit RAM vorbelegen
move.w #256*8-1,d0
5$ move.l #WriteByteRAM,(a0)+
dbra d0,5$
move.l #WriteBytePage0,WriteTab0 ;Zeropage immer speziell
move.l #WriteBytePage0,WriteTab1
move.l #WriteBytePage0,WriteTab2
move.l #WriteBytePage0,WriteTab3
move.l #WriteBytePage0,WriteTab4
move.l #WriteBytePage0,WriteTab5
move.l #WriteBytePage0,WriteTab6
move.l #WriteBytePage0,WriteTab7
lea WriteTab5+208*4,a0 ;I/O-Bereich
move.l #WriteByteVIC,(a0)+
move.l #WriteByteVIC,(a0)+
move.l #WriteByteVIC,(a0)+
move.l #WriteByteVIC,(a0)+
move.l #WriteByteSID,(a0)+
move.l #WriteByteSID,(a0)+
move.l #WriteByteSID,(a0)+
move.l #WriteByteSID,(a0)+
move.l #WriteByteColor,(a0)+
move.l #WriteByteColor,(a0)+
move.l #WriteByteColor,(a0)+
move.l #WriteByteColor,(a0)+
move.l #WriteByteCIA1,(a0)+
move.l #WriteByteCIA2,(a0)+
move.l #WriteByteUndef,(a0)+
move.l #WriteByteUndef,(a0)
lea WriteTab6+208*4,a0
move.l #WriteByteVIC,(a0)+
move.l #WriteByteVIC,(a0)+
move.l #WriteByteVIC,(a0)+
move.l #WriteByteVIC,(a0)+
move.l #WriteByteSID,(a0)+
move.l #WriteByteSID,(a0)+
move.l #WriteByteSID,(a0)+
move.l #WriteByteSID,(a0)+
move.l #WriteByteColor,(a0)+
move.l #WriteByteColor,(a0)+
move.l #WriteByteColor,(a0)+
move.l #WriteByteColor,(a0)+
move.l #WriteByteCIA1,(a0)+
move.l #WriteByteCIA2,(a0)+
move.l #WriteByteUndef,(a0)+
move.l #WriteByteUndef,(a0)
lea WriteTab7+208*4,a0
move.l #WriteByteVIC,(a0)+
move.l #WriteByteVIC,(a0)+
move.l #WriteByteVIC,(a0)+
move.l #WriteByteVIC,(a0)+
move.l #WriteByteSID,(a0)+
move.l #WriteByteSID,(a0)+
move.l #WriteByteSID,(a0)+
move.l #WriteByteSID,(a0)+
move.l #WriteByteColor,(a0)+
move.l #WriteByteColor,(a0)+
move.l #WriteByteColor,(a0)+
move.l #WriteByteColor,(a0)+
move.l #WriteByteCIA1,(a0)+
move.l #WriteByteCIA2,(a0)+
move.l #WriteByteUndef,(a0)+
move.l #WriteByteUndef,(a0)
; JumpTabs aufbauen
lea JumpTab0,a0 ;Alle mit RAM vorbelegen
move.w #256*8-1,d0
6$ move.l #JumpToRAM,(a0)+
dbra d0,6$
lea JumpTab3+160*4,a0 ;Basic-ROM
moveq #31,d0
71$ move.l #JumpToBasic,(a0)+
dbra d0,71$
lea JumpTab7+160*4,a0
moveq #31,d0
72$ move.l #JumpToBasic,(a0)+
dbra d0,72$
lea JumpTab2+224*4,a0 ;Kernal-ROM
moveq #31,d0
81$ move.l #JumpToKernal,(a0)+
dbra d0,81$
lea JumpTab3+224*4,a0
moveq #31,d0
82$ move.l #JumpToKernal,(a0)+
dbra d0,82$
lea JumpTab6+224*4,a0
moveq #31,d0
83$ move.l #JumpToKernal,(a0)+
dbra d0,83$
lea JumpTab7+224*4,a0
moveq #31,d0
84$ move.l #JumpToKernal,(a0)+
dbra d0,84$
lea JumpTab1+208*4,a0 ;Char-ROM
moveq #15,d0
85$ move.l #JumpToChar,(a0)+
dbra d0,85$
lea JumpTab2+208*4,a0
moveq #15,d0
86$ move.l #JumpToChar,(a0)+
dbra d0,86$
lea JumpTab3+208*4,a0
moveq #15,d0
87$ move.l #JumpToChar,(a0)+
dbra d0,87$
lea JumpTab5+208*4,a0 ;I/O-Bereich
moveq #15,d0
88$ move.l #JumpToIO,(a0)+
dbra d0,88$
lea JumpTab6+208*4,a0
moveq #15,d0
89$ move.l #JumpToIO,(a0)+
dbra d0,89$
lea JumpTab7+208*4,a0
moveq #15,d0
810$ move.l #JumpToIO,(a0)+
dbra d0,810$
rts
**
** 6510-Task starten
** Rückgabe: d0#0 = Fehler
**
; Signal einrichten
Start6510 move.l _SysBase,a6
moveq #-1,d0
JSRLIB AllocSignal
move.b d0,ReadySig
moveq #0,d1
bset d0,d1
move.l d1,ReadySet
; Task starten
move.l _DOSBase,a6
move.l #ProcTags,d1
JSRLIB CreateNewProc
move.l d0,CPUProc
beq 1$
; Auf Signal warten
move.l _SysBase,a6
move.l ReadySet,d0
JSRLIB Wait
moveq #0,d0 ;Alles OK
rts
; Fehler aufgetreten
1$ moveq #-1,d0
rts
**
** 6510-Task stoppen
**
; Task stoppen
Stop6510 move.l _SysBase,a6
tst.l CPUProc(pc)
beq 1$
st.b RESETIsEXIT ;EXIT-Reset auslösen
st.b IntIsRESET
move.l ReadySet,d0
JSRLIB Wait
; Signal freigeben
1$ move.b ReadySig,d0
JMPLIB FreeSignal
**
** 6510-Task anhalten
**
Pause6510 move.l _SysBase,a6
st.b RESETIsPause ;Pause-Reset auslösen
st.b IntIsRESET
move.l ReadySet,d0
JMPLIB Wait
**
** 6510-Task fortsetzen
**
Resume6510 move.l _SysBase,a6
move.l CPUTask,a1 ;Continue-Signal schicken
move.l ContinueSet,d0
JMPLIB Signal
**
** Strings in Datenstrukturen lokalisieren
**
GetStr MACRO ;Label
lea TheLocale,a0
move.l #\1,d0
jsr GetString
ENDM
Localize6510 GetStr MSG_REQTITLE
move.l d0,IllegalOpReq+8
move.l d0,JumpToIOReq+8
GetStr MSG_REQGADS3
move.l d0,IllegalOpReq+16
GetStr MSG_REQGADS4
move.l d0,JumpToIOReq+16
GetStr MSG_ILLEGALOP
move.l d0,IllegalOpReq+12
GetStr MSG_JUMPTOIO
move.l d0,JumpToIOReq+12
rts
**
** 6510-Emulator
**
** Register:
** d0: Scratch (Oberes Wort muß IMMER Null sein!)
** d1: Scratch (Oberes Wort muß IMMER Null sein!)
**
; Task ermitteln
CPUTaskProc move.l _SysBase,a6
sub.l a1,a1
JSRLIB FindTask
move.l d0,CPUTask
; Continue-Signal holen
moveq #-1,d0
JSRLIB AllocSignal
move.b d0,ContinueSig
moveq #0,d1
bset d0,d1
move.l d1,ContinueSet
; 6569 initialisieren
bsr Init6569
; Signal an den Emulator schicken
move.l _SysBase,a6
move.l MainTask,a1
move.l ReadySet,d0
JSRLIB Signal
; Variablen initilisieren
clr.l Interrupt
clr.b RESETIsEXIT
clr.b RESETIsPause
move.w #63,CyclesLeft
; Speicherkonfiguration initialisieren
move.l TheRAM,RAMPTR
move.w #$ff07,(RAMPTR)
NewConfig
; Register setzen
moveq #0,d0
moveq #0,d1
moveq #0,RA
moveq #0,RX
moveq #0,RY
move.l #$01ff,RS
moveq #0,RCCR
move.l #InterruptMask,RP
lea OpcodeTable,OPTABPTR
; Reset-Vektor lesen, PC setzen und ersten Befehl ausführen
move.w #$fffc,d0
ReadWord
Jump
Next 0
; Unbekannten Opcode entdeckt: Requester darstellen
IllegalOp movem.l a2-a6,-(sp)
and.w #$00ff,d0 ;Opcode
move.w d0,RequestStream
move.l RPC,d0 ;und PC anzeigen
subq.w #1,d0
move.w d0,RequestStream+2
bsr AmigaToFront
move.l _IntuitionBase,a6
sub.l a0,a0
lea IllegalOpReq,a1
move.l a0,a2
lea RequestStream,a3
JSRLIB EasyRequestArgs
move.l d0,-(sp)
bsr EmulToFront
move.l (sp)+,d0
movem.l (sp)+,a2-a6
tst.l d0
beq 1$
bsr Reset6526 ;Reset
bsr Reset6581
moveq #0,d0 ;MSWs von d0 und d1
moveq #0,d1 ; müssen Null sein
bra HandleRESET
1$ moveq #0,d0 ;Weiter
moveq #0,d1
Next 0
**
** Speicherzugriff Lesen
** In a1 steht die Rücksprungadresse
**
; Lesen aus dem RAM
ReadByteRAM move.b (RAMPTR,d0.l),d0
jmp (a1)
; Lesen aus dem Basic-ROM
ReadByteBasic and.w #$1fff,d0
move.b ([TheBasic,pc],d0.w),d0
jmp (a1)
; Lesen aus einem VIC-Register
ReadByteVIC and.w #$3f,d0
bsr ReadFrom6569
jmp (a1)
; Lesen aus einem SID-Register
ReadByteSID and.w #$1f,d0
bsr ReadFrom6581
jmp (a1)
; Lesen aus dem Farb-RAM
ReadByteColor and.w #$03ff,d0
move.b ([TheColor,pc],d0.w),d1
and.b #$0f,d1
move.l d1,-(sp)
bsr Random ;Oberes Nibble ist Zufallswert
and.b #$f0,d0
move.l (sp)+,d1
or.b d1,d0
jmp (a1)
; Lesen aus einem CIA 1-Register
ReadByteCIA1 and.w #$0f,d0
bsr ReadFrom6526A
jmp (a1)
; Lesen aus einem CIA 2-Register
ReadByteCIA2 and.w #$0f,d0
bsr ReadFrom6526B
jmp (a1)
; Lesen einer offenen Adresse
ReadByteUndef cmp.l #$dfa0,d0
bhs 1$
bsr Random ;Zufallswert
moveq #0,d1 ;MSW löschen
jmp (a1)
; $dfa0-$dfff: Emulator-Identifikation
1$ cmp.w #$dfff,d0 ;$dfff liest abwechselnd $55/$aa
bne 2$
move.b DFFFByte,d0
not.b DFFFByte
jmp (a1)
2$ cmp.w #$dffe,d0 ;$dffe liest "F" (Frodo-Kennung)
bne 3$
moveq #'F',d0
jmp (a1)
3$ cmp.w #$dffd,d0 ;$dffd: Version
bne 4$
move.b #VERSION,d0
jmp (a1)
4$ cmp.w #$dffc,d0 ;$dffc: Revision
bne 5$
move.b #REVISION,d0
jmp (a1)
5$ sub.w #$dfa0,d0 ;$dfa0-$dffb: ID-String
move.b IDString(pc,d0.w),d0
jmp (a1)
; Lesen aus dem Kernal-ROM
ReadByteKernal and.w #$1fff,d0
move.b ([TheKernal,pc],d0.w),d0
jmp (a1)
; Lesen aus dem Char-ROM
ReadByteChar and.w #$0fff,d0
move.b ([TheChar,pc],d0.w),d0
jmp (a1)
**
** Speicherzugriff Schreiben
** In a1 steht die 16-Bit-Adresse
**
; Schreiben in Seite 0
WriteBytePage0 move.l a1,d0
move.b d1,(RAMPTR,d0.w)
cmp.b #2,d0
bhs 1$
NewConfig
1$ rts
; Schreiben ins RAM
WriteByteRAM move.b d1,(RAMPTR,a1.l)
rts
; Schreiben in ein VIC-Register
WriteByteVIC move.l a1,d0
and.w #$3f,d0
bra WriteTo6569
; Schreiben in ein SID-Register
WriteByteSID move.l a1,d0
and.w #$1f,d0
bra WriteTo6581
; Schreiben ins Farb-RAM
WriteByteColor move.l a1,d0
and.w #$03ff,d0
move.b d1,([TheColor],d0.w)
rts
; Schreiben in ein CIA 1-Register
WriteByteCIA1 move.l a1,d0
and.w #$0f,d0
bra WriteTo6526A
; Schreiben in ein CIA 2-Register
WriteByteCIA2 move.l a1,d0
and.w #$0f,d0
bra WriteTo6526B
; Schreiben an einer offenen Adresse
WriteByteUndef move.l a1,d0
rts
**
** Sprungbefehle
**
; Sprung ins RAM
JumpToRAM lea (RAMPTR,d0.l),RPC
rts
; Sprung ins Basic-ROM
JumpToBasic move.l TheBasic(pc),RPC
and.w #$1fff,d0
add.l d0,RPC
rts
; Sprung ins Kernal-ROM
JumpToKernal move.l TheKernal(pc),RPC
and.w #$1fff,d0
add.l d0,RPC
rts
; Sprung ins Char-ROM (warum sollte jemand sowas tun? Aber egal.)
JumpToChar move.l TheChar(pc),RPC
and.w #$0fff,d0
add.l d0,RPC
rts
; Sprung in den I/O-Bereich (in VIC-Register wird ab und zu gerne gesprungen,
; $de00 und das Farb-RAM sind auch sehr beliebt :-)
JumpToIO movem.l a2-a6,-(sp)
move.w d0,RequestStream ;PC anzeigen
bsr AmigaToFront
move.l _IntuitionBase,a6
sub.l a0,a0
lea JumpToIOReq,a1
move.l a0,a2
lea RequestStream,a3
JSRLIB EasyRequestArgs
bsr EmulToFront
movem.l (sp)+,a2-a6
bsr Reset6526
bsr Reset6581
moveq #0,d0 ;MSWs von d0 und d1
moveq #0,d1 ; müssen Null sein
addq.l #4,sp ;Rücksprungadresse löschen
bra HandleRESET
**
** Opcode-Routinen
**
*
* Interrupts handhaben
*
; Art des Interrupt feststellen (Priorität)
HandleInt tst.b IntIsRESET(pc)
bne HandleRESET
tst.b IntIsNMI(pc)
bne HandleNMI
tst.b IntIsVICIRQ(pc)
bne HandleVICIRQ
tst.b IntIsCIAIRQ(pc)
bne HandleCIAIRQ
; Kein Interrupt, nächsten Befehl ausführen
HandleIntDone Next 0
; IRQ: Interrupt-Bit testen, nach ($fffe) springen
HandleVICIRQ btst #InterruptBit,RP
beq HandleIRQ
Next 0
HandleCIAIRQ btst #InterruptBit,RP
beq HandleIRQ
Next 0
HandleIRQ PushPC
PushP
or.w #InterruptMask,RP
move.w #$fffe,d0 ;IRQ-Vektor
ReadWord
Jump
Next 7
; NMI: Nach ($fffa) springen
HandleNMI clr.b IntIsNMI ;Simuliert einen flankengetriggerten Eingang
PushPC
PushP
or.w #InterruptMask,RP
move.w #$fffa,d0 ;NMI-Vektor
ReadWord
Jump
Next 7
; RESET: Emulator beenden oder nach ($fffc) springen
HandleRESET tst.b RESETIsEXIT ;Beenden?
bne HandleEXIT
tst.b RESETIsPause ;Pause?
bne HandlePause
clr.l Interrupt ;Nein, RESET
cmp.l #$c3c2cd38,$8004(RAMPTR)
bne 1$
cmp.b #$30,$8008(RAMPTR)
bne 1$
clr.b $8004(RAMPTR) ;CBM80 löschen, wenn vorhanden
1$ move.w #$ff07,(RAMPTR) ;Speicherkonfiguration initialisieren
NewConfig
move.w #$fffc,d0 ;RESET-Vektor
ReadWord
Jump
Next 0
; EXIT: Signal an den Emulator schicken
HandleEXIT bsr Exit6569 ;6569 aufräumen
move.l _SysBase,a6
moveq #0,d0
move.b ContinueSig,d0
JSRLIB FreeSignal
JSRLIB Forbid
move.l MainTask,a1
move.l ReadySet,d0
JSRLIB Signal
moveq #0,d0
rts
; Pause: Signal an den Emulator schicken und dann selbst auf
; ein Signal warten
HandlePause clr.l Interrupt
clr.b RESETIsPause
movem.l d2-d7/a2-a6,-(sp)
move.l _SysBase,a6
move.l MainTask,a1
move.l ReadySet,d0
JSRLIB Signal
move.l ContinueSet,d0
JSRLIB Wait
movem.l (sp)+,d2-d7/a2-a6
moveq #0,d0
moveq #0,d1
Next 0
*
* Opcodes
*
; Laden
LoadA MACRO ;Quelle, Zyklenzahl
move.b \1,RA
move ccr,RCCR
Next \2
ENDM
LoadX MACRO ;Quelle, Zyklenzahl
move.b \1,RX
move ccr,RCCR
Next \2
ENDM
LoadY MACRO ;Quelle, Zyklenzahl
move.b \1,RY
move ccr,RCCR
Next \2
ENDM
LoadAX MACRO ;Quelle, Zyklenzahl
move.b \1,RA
move.b RA,RX
move ccr,RCCR
Next \2
ENDM
LDAImm LoadA (RPC)+,2
LDAZero ReadAdrZero
LoadA (RAMPTR,d0.w),3
LDAZeroX ReadAdrZeroX
LoadA (RAMPTR,d0.w),4
LDAAbs ReadByteAbs
LoadA d0,4
LDAAbsX ReadByteAbsX
LoadA d0,4
LDAAbsY ReadByteAbsY
LoadA d0,4
LDAIndX ReadByteIndX
LoadA d0,6
LDAIndY ReadByteIndY
LoadA d0,5
LDXImm LoadX (RPC)+,2
LDXZero ReadAdrZero
LoadX (RAMPTR,d0.w),3
LDXZeroY ReadAdrZeroY
LoadX (RAMPTR,d0.w),4
LDXAbs ReadByteAbs
LoadX d0,4
LDXAbsY ReadByteAbsY
LoadX d0,4
LDYImm LoadY (RPC)+,2
LDYZero ReadAdrZero
LoadY (RAMPTR,d0.w),3
LDYZeroX ReadAdrZeroX
LoadY (RAMPTR,d0.w),4
LDYAbs ReadByteAbs
LoadY d0,4
LDYAbsX ReadByteAbsX
LoadY d0,4
LAXZero ReadAdrZero
LoadAX (RAMPTR,d0.w),3
LAXZeroY ReadAdrZeroY
LoadAX (RAMPTR,d0.w),4
LAXAbs ReadByteAbs
LoadAX d0,4
LAXAbsY ReadByteAbsY
LoadAX d0,4
LAXIndX ReadByteIndX
LoadAX d0,6
LAXIndY ReadByteIndY
LoadAX d0,5
; Speichern
StoreA MACRO ;Zyklenzahl
move.b RA,d1
WriteByte
Next \1
ENDM
StoreAX MACRO ;Zyklenzahl
move.b RA,d1
and.b RX,d1
WriteByte
Next \1
ENDM
STAZero ReadAdrZero
WriteZeroNext RA,3
STAZeroX ReadAdrZeroX
WriteZeroNext RA,4
STAAbs ReadAdrAbs
StoreA 4
STAAbsX ReadAdrAbsX
StoreA 5
STAAbsY ReadAdrAbsY
StoreA 5
STAIndX ReadAdrIndX
StoreA 6
STAIndY ReadAdrIndY
StoreA 6
STXZero ReadAdrZero
WriteZeroNext RX,3
STXZeroY ReadAdrZeroY
WriteZeroNext RX,4
STXAbs ReadAdrAbs
move.b RX,d1
WriteByte
Next 4
STYZero ReadAdrZero
WriteZeroNext RY,3
STYZeroX ReadAdrZeroX
WriteZeroNext RY,4
STYAbs ReadAdrAbs
move.b RY,d1
WriteByte
Next 4
SAXZero ReadAdrZero
StoreAX 3
SAXZeroY ReadAdrZeroY
StoreAX 4
SAXAbs ReadAdrAbs
StoreAX 4
SAXIndX ReadAdrIndX
StoreAX 6
; Datentransport zwischen Registern
TAX move.b RA,RX
move ccr,RCCR
Next 2
TAY move.b RA,RY
move ccr,RCCR
Next 2
TXA move.b RX,RA
move ccr,RCCR
Next 2
TYA move.b RY,RA
move ccr,RCCR
Next 2
TXS move.b RX,RS
Next 2
TSX move.b RS,RX
move ccr,RCCR
Next 2
; Stack
PHA PushByte RA
Next 3
PLA PopByte RA
move ccr,RCCR
Next 4
PHP or.w #BreakMask,RP ;Prozessorfehler: Break-Flag
PushP ; wird auf dem Stack gesetzt
and.w #~BreakMask,RP
Next 3
PLP PopP
tst.w IntIsIRQ(pc) ;Steht ein IRQ an?
beq 1$
btst #InterruptBit,RP ;Ja, I-Flag gelöscht?
beq HandleIRQ ;Ja, Interrupt auslösen
1$ Next 4
; Vergleiche
CompareA MACRO ;Quelle, Zyklenzahl
cmp.b \1,RA
move ccr,RCCR
move.b RCCR,RP ;Carry holen und invertieren
not.b RP
Next \2
ENDM
CMPImm CompareA (RPC)+,2
CMPZero ReadAdrZero
CompareA (RAMPTR,d0.w),3
CMPZeroX ReadAdrZeroX
CompareA (RAMPTR,d0.w),4
CMPAbs ReadByteAbs
CompareA d0,4
CMPAbsX ReadByteAbsX
CompareA d0,4
CMPAbsY ReadByteAbsY
CompareA d0,4
CMPIndX ReadByteIndX
CompareA d0,6
CMPIndY ReadByteIndY
CompareA d0,5
CPXImm cmp.b (RPC)+,RX
move ccr,RCCR
move.b RCCR,RP ;Carry holen und invertieren
not.b RP
Next 2
CPXZero ReadAdrZero
cmp.b (RAMPTR,d0.w),RX
move ccr,RCCR
move.b RCCR,RP ;Carry holen und invertieren
not.b RP
Next 3
CPXAbs ReadByteAbs
cmp.b d0,RX
move ccr,RCCR
move.b RCCR,RP ;Carry holen und invertieren
not.b RP
Next 4
CPYImm cmp.b (RPC)+,RY
move ccr,RCCR
move.b RCCR,RP ;Carry holen und invertieren
not.b RP
Next 2
CPYZero ReadAdrZero
cmp.b (RAMPTR,d0.w),RY
move ccr,RCCR
move.b RCCR,RP ;Carry holen und invertieren
not.b RP
Next 3
CPYAbs ReadByteAbs
cmp.b d0,RY
move ccr,RCCR
move.b RCCR,RP ;Carry holen und invertieren
not.b RP
Next 4
; Arithmetische Operationen
AdcA MACRO ;Zyklenzahl
lsr.b #1,RP ;Carry -> X
btst #DecimalBit,RP
bne \@1$
addx.b d0,RA
move ccr,RCCR
bvc \@2$ ;Overflow holen
or.w #OverflowMask,RP
move.b RCCR,RP ;Carry holen
Next \1
\@2$ and.w #~OverflowMask,RP
move.b RCCR,RP ;Carry holen
Next \1
\@1$ moveq #0,d1 ;V und C löschen
abcd.b d0,RA
move ccr,RCCR
bvc \@2$ ;Overflow holen
or.w #OverflowMask,RP
move.b RCCR,RP ;Carry holen
Next \1
ENDM
ADCImm move.b (RPC)+,d0
AdcA 2
ADCZero ReadByteZero d0
AdcA 3
ADCZeroX ReadByteZeroX d0
AdcA 4
ADCAbs ReadByteAbs
AdcA 4
ADCAbsX ReadByteAbsX
AdcA 4
ADCAbsY ReadByteAbsY
AdcA 4
ADCIndX ReadByteIndX
AdcA 6
ADCIndY ReadByteIndY
AdcA 5
SbcA MACRO ;Zyklenzahl
not.b RP
lsr.b #1,RP ;Carry invertieren und nach X
btst #DecimalBit,RP
bne \@1$
subx.b d0,RA
move ccr,RCCR
bvc \@2$ ;Overflow holen
or.w #OverflowMask,RP
move.b RCCR,RP ;Carry holen und invertieren
not.b RP
Next \1
\@2$ and.w #~OverflowMask,RP
move.b RCCR,RP ;Carry holen und invertieren
not.b RP
Next \1
\@1$ moveq #0,d1 ;V und C löschen
sbcd.b d0,RA
move ccr,RCCR
bvc \@2$ ;Overflow holen
or.w #OverflowMask,RP
move.b RCCR,RP ;Carry holen und invertieren
not.b RP
Next \1
ENDM
SBCImm move.b (RPC)+,d0
SbcA 2
SBCZero ReadByteZero d0
SbcA 3
SBCZeroX ReadByteZeroX d0
SbcA 4
SBCAbs ReadByteAbs
SbcA 4
SBCAbsX ReadByteAbsX
SbcA 4
SBCAbsY ReadByteAbsY
SbcA 4
SBCIndX ReadByteIndX
SbcA 6
SBCIndY ReadByteIndY
SbcA 5
Increment MACRO ;Zyklenzahl
move.l d0,-(sp)
ReadByte
addq.b #1,d0
move ccr,RCCR
move.b d0,d1
move.l (sp)+,d0
WriteByte
Next \1
ENDM
IncrementZero MACRO ;Zyklenzahl
addq.b #1,(RAMPTR,d0.w)
move ccr,RCCR
cmp.b #2,d0
bhs \@1$
NewConfig
\@1$ Next \1
ENDM
INCZero ReadAdrZero
IncrementZero 5
INCZeroX ReadAdrZeroX
IncrementZero 6
INCAbs ReadAdrAbs
Increment 6
INCAbsX ReadAdrAbsX
Increment 7
Decrement MACRO ;Zyklenzahl
move.l d0,-(sp)
ReadByte
subq.b #1,d0
move ccr,RCCR
move.b d0,d1
move.l (sp)+,d0
WriteByte
Next \1
ENDM
DecrementZero MACRO ;Zyklenzahl
subq.b #1,(RAMPTR,d0.w)
move ccr,RCCR
cmp.b #2,d0
bhs \@1$
NewConfig
\@1$ Next \1
ENDM
DECZero ReadAdrZero
DecrementZero 5
DECZeroX ReadAdrZeroX
DecrementZero 6
DECAbs ReadAdrAbs
Decrement 6
DECAbsX ReadAdrAbsX
Decrement 7
INX addq.b #1,RX
move ccr,RCCR
Next 2
DEX subq.b #1,RX
move ccr,RCCR
Next 2
INY addq.b #1,RY
move ccr,RCCR
Next 2
DEY subq.b #1,RY
move ccr,RCCR
Next 2
; Logische Operationen
AndA MACRO ;Quelle, Zyklenzahl
and.b \1,RA
move ccr,RCCR
Next \2
ENDM
ANDImm AndA (RPC)+,2
ANDZero ReadAdrZero
AndA (RAMPTR,d0.w),3
ANDZeroX ReadAdrZeroX
AndA (RAMPTR,d0.w),4
ANDAbs ReadByteAbs
AndA d0,4
ANDAbsX ReadByteAbsX
AndA d0,4
ANDAbsY ReadByteAbsY
AndA d0,4
ANDIndX ReadByteIndX
AndA d0,6
ANDIndY ReadByteIndY
AndA d0,5
OrA MACRO ;Quelle, Zyklenzahl
or.b \1,RA
move ccr,RCCR
Next \2
ENDM
ORAImm OrA (RPC)+,2
ORAZero ReadAdrZero
OrA (RAMPTR,d0.w),3
ORAZeroX ReadAdrZeroX
OrA (RAMPTR,d0.w),4
ORAAbs ReadByteAbs
OrA d0,4
ORAAbsX ReadByteAbsX
OrA d0,4
ORAAbsY ReadByteAbsY
OrA d0,4
ORAIndX ReadByteIndX
OrA d0,6
ORAIndY ReadByteIndY
OrA d0,5
EorA MACRO ;Zyklenzahl
eor.b d0,RA ;eor.b (ea),RA geht nicht
move ccr,RCCR ;(Warum nicht, Motorola ?) :-(
Next \1
ENDM
EORImm move.b (RPC)+,d0
EorA 2
EORZero ReadAdrZero
move.b (RAMPTR,d0.w),d0
EorA 3
EORZeroX ReadAdrZeroX
move.b (RAMPTR,d0.w),d0
EorA 4
EORAbs ReadByteAbs
EorA 4
EORAbsX ReadByteAbsX
EorA 4
EORAbsY ReadByteAbsY
EorA 4
EORIndX ReadByteIndX
EorA 6
EORIndY ReadByteIndY
EorA 5
BitTest MACRO ;Zyklenzahl
tst.b d0 ;N holen
move ccr,RCCR
and.w #$1cff,RP ;B,D,I und C behalten
btst #6,d0 ;Bit 6 -> V
beq \@1$
or.w #OverflowMask,RP
\@1$ and.b RA,d0 ;A AND M -> Z
beq \@2$
and.b #$fb,RCCR
Next \1
\@2$ or.b #$04,RCCR
Next \1
ENDM
BITZero ReadByteZero d0
BitTest 3
BITAbs ReadByteAbs
BitTest 4
; Verschiebungen
ShiftLeft MACRO ;Zyklenzahl
move.l d0,-(sp)
ReadByte
add.b d0,d0
move ccr,RCCR
move.b RCCR,RP ;Carry holen
move.b d0,d1
move.l (sp)+,d0
WriteByte
Next \1
ENDM
ShiftLeftZero MACRO ;Zyklenzahl
lea (RAMPTR,d0.w),a0
move.b (a0),d1
add.b d1,d1
move ccr,RCCR
move.b RCCR,RP ;Carry holen
move.b d1,(a0)
cmp.b #2,d0
bhs \@1$
NewConfig
\@1$ Next \1
ENDM
ASLA add.b RA,RA
move ccr,RCCR
move.b RCCR,RP ;Carry holen
Next 2
ASLZero ReadAdrZero
ShiftLeftZero 5
ASLZeroX ReadAdrZeroX
ShiftLeftZero 6
ASLAbs ReadAdrAbs
ShiftLeft 6
ASLAbsX ReadAdrAbsX
ShiftLeft 7
ShiftRight MACRO ;Zyklenzahl
move.l d0,-(sp)
ReadByte
lsr.b #1,d0
move ccr,RCCR
move.b RCCR,RP ;Carry holen
move.b d0,d1
move.l (sp)+,d0
WriteByte
Next \1
ENDM
ShiftRightZero MACRO ;Zyklenzahl
lea (RAMPTR,d0.w),a0
move.b (a0),d1
lsr.b #1,d1
move ccr,RCCR
move.b RCCR,RP ;Carry holen
move.b d1,(a0)
cmp.b #2,d0
bhs \@1$
NewConfig
\@1$ Next \1
ENDM
LSRA lsr.b #1,RA
move ccr,RCCR
move.b RCCR,RP ;Carry holen
Next 2
LSRZero ReadAdrZero
ShiftRightZero 5
LSRZeroX ReadAdrZeroX
ShiftRightZero 6
LSRAbs ReadAdrAbs
ShiftRight 6
LSRAbsX ReadAdrAbsX
ShiftRight 7
RotateLeft MACRO ;Zyklenzahl
move.l d0,-(sp)
ReadByte
lsr.b #1,RP ;Carry -> X
roxl.b #1,d0
move ccr,RCCR
move.b RCCR,RP ;Carry holen
move.b d0,d1
move.l (sp)+,d0
WriteByte
Next \1
ENDM
RotateLeftZero MACRO ;Zyklenzahl
lea (RAMPTR,d0.w),a0
move.b (a0),d1
lsr.b #1,RP ;Carry -> X
roxl.b #1,d1
move ccr,RCCR
move.b RCCR,RP ;Carry holen
move.b d1,(a0)
cmp.b #2,d0
bhs \@1$
NewConfig
\@1$ Next \1
ENDM
ROLA lsr.b #1,RP ;Carry -> X
roxl.b #1,RA
move ccr,RCCR
move.b RCCR,RP ;Carry holen
Next 2
ROLZero ReadAdrZero
RotateLeftZero 5
ROLZeroX ReadAdrZeroX
RotateLeftZero 6
ROLAbs ReadAdrAbs
RotateLeft 6
ROLAbsX ReadAdrAbsX
RotateLeft 7
RotateRight MACRO ;Zyklenzahl
move.l d0,-(sp)
ReadByte
lsr.b #1,RP ;Carry -> X
roxr.b #1,d0
move ccr,RCCR
move.b RCCR,RP ;Carry holen
move.b d0,d1
move.l (sp)+,d0
WriteByte
Next \1
ENDM
RotateRightZero MACRO ;Zyklenzahl
lea (RAMPTR,d0.w),a0
move.b (a0),d1
lsr.b #1,RP ;Carry -> X
roxr.b #1,d1
move ccr,RCCR
move.b RCCR,RP ;Carry holen
move.b d1,(a0)
cmp.b #2,d0
bhs \@1$
NewConfig
\@1$ Next \1
ENDM
RORA lsr.b #1,RP ;Carry -> X
roxr.b #1,RA
move ccr,RCCR
move.b RCCR,RP ;Carry holen
Next 2
RORZero ReadAdrZero
RotateRightZero 5
RORZeroX ReadAdrZeroX
RotateRightZero 6
RORAbs ReadAdrAbs
RotateRight 6
RORAbsX ReadAdrAbsX
RotateRight 7
; Sprünge/Verzweigungen
JMPAbs ReadAdrAbs
Jump
Next 3
JMPInd ReadAdrInd
Jump
Next 5
JSRAbs PushPCPlus1
ReadAdrAbs
Jump
Next 6
RTSImpl PopByte d1 ;LSB
PopByte d0 ;MSB
lsl.w #8,d0 ;schieben
move.b d1,d0 ;LSB dazunehmen
addq.w #1,d0 ;Adresse um eins erhöhen
Jump
Next 6
RTIImpl PopP
PopByte d1 ;LSB
PopByte d0 ;MSB
lsl.w #8,d0 ;schieben
move.b d1,d0 ;LSB dazunehmen
Jump
tst.w IntIsIRQ(pc) ;Steht ein IRQ an?
beq 1$
btst #InterruptBit,RP ;Ja, I-Flag gelöscht?
beq HandleIRQ ;Ja, Interrupt auslösen
1$ Next 6
BRK PushPC
or.w #BreakMask,RP ;Break-Flag nur auf dem Stapel setzen
PushP
and.w #~BreakMask,RP
or.w #InterruptMask,RP
move.w #$fffe,d0 ;IRQ-Vektor
ReadWord
Jump
Next 7
Branch MACRO
ReadByteRel
move.l RPC,d1
add.w d0,d1
move.l d1,RPC
moveq #0,d1
Next 3
ENDM
BVCRel btst #OverflowBit,RP
bne BVCNot
Branch
BVCNot addq.l #1,RPC
Next 2
BVSRel btst #OverflowBit,RP
beq BVSNot
Branch
BVSNot addq.l #1,RPC
Next 2
BEQRel btst #2,RCCR
beq BEQNot
Branch
BEQNot addq.l #1,RPC
Next 2
BNERel btst #2,RCCR
bne BNENot
Branch
BNENot addq.l #1,RPC
Next 2
BPLRel btst #3,RCCR
bne BPLNot
Branch
BPLNot addq.l #1,RPC
Next 2
BMIRel btst #3,RCCR
beq BMINot
Branch
BMINot addq.l #1,RPC
Next 2
BCCRel btst #CarryBit,RP
bne BCCNot
Branch
BCCNot addq.l #1,RPC
Next 2
BCSRel btst #CarryBit,RP
beq BCSNot
Branch
BCSNot addq.l #1,RPC
Next 2
; Statusregister
SEI or.w #InterruptMask,RP
Next 2
CLI and.w #~InterruptMask,RP
tst.w IntIsIRQ(pc) ;Steht ein IRQ an?
bne HandleIRQ ;Ja, auslösen
Next 2
CLC clr.b RP
Next 2
SEC st.b RP
Next 2
SED or.w #DecimalMask,RP
Next 2
CLD and.w #~DecimalMask,RP
Next 2
CLV and.w #~OverflowMask,RP
Next 2
*
* Periodic: Wird über den Opcode-Fetch aufgerufen,
* wenn der Zyklenzähler unterläuft
* Sitzt hier in der Mitte, um kurze Branches ausnutzen zu können
*
; VIC und CIA aufrufen
Periodic lea RegStore+24,a0
movem.w d2-d7,-(a0) ;Gerade Anzahl von Registern
movem.l a2-a3/a5,-(a0)
bra Periodic6569 ;Springt nach Periodic6526 und hierher zurück
Peri6526Cont movem.l RegStore,a2-a3/a5
movem.w RegStore+12,d2-d7
move.l TheRAM,RAMPTR ;a4
lea OpcodeTable,OPTABPTR ;a6
moveq #0,d0
moveq #0,d1
; Interrupt aufgetreten?
tst.l Interrupt(pc)
bne HandleInt
; Nein, Nächsten Befehl ausführen
Next 0
; Leerbefehle
NOPImpl Next 2
NOPZero addq.w #1,RPC
Next 3
NOPZeroX addq.w #1,RPC
Next 4
NOPAbsX
NOPAbs addq.w #2,RPC
Next 4
; ASL/ORA-Gruppe
ShLeftOr MACRO ;Zyklenzahl
move.l d0,-(sp)
ReadByte
add.b d0,d0
move ccr,RCCR
move.b RCCR,RP ;Carry holen
or.b d0,RA
move.b d0,d1
move.l (sp)+,d0
WriteByte
Next \1
ENDM
ShLeftOrZero MACRO ;Zyklenzahl
lea (RAMPTR,d0.w),a0
move.b (a0),d1
add.b d1,d1
move ccr,RCCR
move.b RCCR,RP ;Carry holen
or.b d1,RA
move.b d1,(a0)
cmp.b #2,d0
bhs \@1$
NewConfig
\@1$ Next \1
ENDM
SLOZero ReadAdrZero
ShLeftOrZero 5
SLOZeroX ReadAdrZeroX
ShLeftOrZero 6
SLOAbs ReadAdrAbs
ShLeftOr 6
SLOAbsX ReadAdrAbsX
ShLeftOr 7
SLOAbsY ReadAdrAbsY
ShLeftOr 7
SLOIndX ReadAdrIndX
ShLeftOr 8
SLOIndY ReadAdrIndY
ShLeftOr 8
; ROL/AND-Gruppe
RoLeftAnd MACRO ;Zyklenzahl
move.l d0,-(sp)
ReadByte
lsr.b #1,RP ;Carry -> X
roxl.b #1,d0
move ccr,RCCR
move.b RCCR,RP ;Carry holen
and.b d0,RA
move ccr,RCCR ;N und Z holen
move.b d0,d1
move.l (sp)+,d0
WriteByte
Next \1
ENDM
RoLeftAndZero MACRO ;Zyklenzahl
lea (RAMPTR,d0.w),a0
move.b (a0),d1
lsr.b #1,RP ;Carry -> X
roxl.b #1,d1
move ccr,RCCR
move.b RCCR,RP ;Carry holen
and.b d1,RA
move ccr,RCCR ;N und Z holen
move.b d1,(a0)
cmp.b #2,d0
bhs \@1$
NewConfig
\@1$ Next \1
ENDM
RLAZero ReadAdrZero
RoLeftAndZero 5
RLAZeroX ReadAdrZeroX
RoLeftAndZero 6
RLAAbs ReadAdrAbs
RoLeftAnd 6
RLAAbsX ReadAdrAbsX
RoLeftAnd 7
RLAAbsY ReadAdrAbsY
RoLeftAnd 7
RLAIndX ReadAdrIndX
RoLeftAnd 8
RLAIndY ReadAdrIndY
RoLeftAnd 8
; LSR/EOR-Gruppe
ShRightEor MACRO ;Zyklenzahl
move.l d0,-(sp)
ReadByte
lsr.b #1,d0
move ccr,RCCR
move.b RCCR,RP ;Carry holen
eor.b d0,RA
move.b d0,d1
move.l (sp)+,d0
WriteByte
Next \1
ENDM
ShRightEorZero MACRO ;Zyklenzahl
lea (RAMPTR,d0.w),a0
move.b (a0),d1
lsr.b #1,d1
move ccr,RCCR
move.b RCCR,RP ;Carry holen
eor.b d1,RA
move.b d1,(a0)
cmp.b #2,d0
bhs \@1$
NewConfig
\@1$ Next \1
ENDM
SREZero ReadAdrZero
ShRightEorZero 5
SREZeroX ReadAdrZeroX
ShRightEorZero 6
SREAbs ReadAdrAbs
ShRightEor 6
SREAbsX ReadAdrAbsX
ShRightEor 7
SREAbsY ReadAdrAbsY
ShRightEor 7
SREIndX ReadAdrIndX
ShRightEor 8
SREIndY ReadAdrIndY
ShRightEor 8
; ROR/ADC-Gruppe
RoRightAdc MACRO ;Zyklenzahl
move.l d0,-(sp)
ReadByte
lsr.b #1,RP ;Carry -> X
roxr.b #1,d0
move ccr,RCCR
move.b RCCR,RP ;Carry holen
lsr.b #1,RP ;Carry -> X
addx.b d0,RA
move ccr,RCCR
bvc \@2$ ;Overflow holen
or.w #OverflowMask,RP
bra \@3$
\@2$ and.w #~OverflowMask,RP
\@3$ move.b RCCR,RP ;Carry holen
move.b d0,d1
move.l (sp)+,d0
WriteByte
Next \1
ENDM
RoRightAdcZero MACRO ;Zyklenzahl
lea (RAMPTR,d0.w),a0
move.b (a0),d1
lsr.b #1,RP ;Carry -> X
roxr.b #1,d1
move ccr,RCCR
move.b RCCR,RP ;Carry holen
lsr.b #1,RP ;Carry -> X
addx.b d1,RA
move ccr,RCCR
bvc \@2$ ;Overflow holen
or.w #OverflowMask,RP
bra \@3$
\@2$ and.w #~OverflowMask,RP
\@3$ move.b RCCR,RP ;Carry holen
move.b d1,(a0)
cmp.b #2,d0
bhs \@1$
NewConfig
\@1$ Next \1
ENDM
RRAZero ReadAdrZero
RoRightAdcZero 5
RRAZeroX ReadAdrZeroX
RoRightAdcZero 6
RRAAbs ReadAdrAbs
RoRightAdc 6
RRAAbsX ReadAdrAbsX
RoRightAdc 7
RRAAbsY ReadAdrAbsY
RoRightAdc 7
RRAIndX ReadAdrIndX
RoRightAdc 8
RRAIndY ReadAdrIndY
RoRightAdc 8
; DEC/CMP-Gruppe
DecCompare MACRO ;Zyklenzahl
move.l d0,-(sp)
ReadByte
subq.b #1,d0
cmp.b d0,RA
move ccr,RCCR
move.b RCCR,RP ;Carry holen und invertieren
not.b RP
move.b d0,d1
move.l (sp)+,d0
WriteByte
Next \1
ENDM
DecCompareZero MACRO ;Zyklenzahl
lea (RAMPTR,d0.w),a0
move.b (a0),d1
subq.b #1,d1
cmp.b d1,RA
move ccr,RCCR
move.b RCCR,RP ;Carry holen und invertieren
not.b RP
move.b d1,(a0)
cmp.b #2,d0
bhs \@1$
NewConfig
\@1$ Next \1
ENDM
DCPZero ReadAdrZero
DecCompareZero 5
DCPZeroX ReadAdrZeroX
DecCompareZero 6
DCPAbs ReadAdrAbs
DecCompare 6
DCPAbsX ReadAdrAbsX
DecCompare 7
DCPAbsY ReadAdrAbsY
DecCompare 7
DCPIndX ReadAdrIndX
DecCompare 8
DCPIndY ReadAdrIndY
DecCompare 8
; INC/SBC-Gruppe
IncSbc MACRO ;Zyklenzahl
move.l d0,-(sp)
ReadByte
addq.b #1,d0
not.b RP
lsr.b #1,RP ;Carry invertieren und nach X
subx.b d0,RA
move ccr,RCCR
bvc \@2$ ;Overflow holen
or.w #OverflowMask,RP
bra \@3$
\@2$ and.w #~OverflowMask,RP
\@3$ move.b RCCR,RP ;Carry holen und invertieren
not.b RP
move.b d0,d1
move.l (sp)+,d0
WriteByte
Next \1
ENDM
IncSbcZero MACRO ;Zyklenzahl
lea (RAMPTR,d0.w),a0
move.b (a0),d1
addq.b #1,d1
not.b RP
lsr.b #1,RP ;Carry invertieren und nach X
subx.b d1,RA
move ccr,RCCR
bvc \@2$ ;Overflow holen
or.w #OverflowMask,RP
bra \@3$
\@2$ and.w #~OverflowMask,RP
\@3$ move.b RCCR,RP ;Carry holen und invertieren
not.b RP
move.b d1,(a0)
cmp.b #2,d0
bhs \@1$
NewConfig
\@1$ Next \1
ENDM
ISBZero ReadAdrZero
IncSbcZero 5
ISBZeroX ReadAdrZeroX
IncSbcZero 6
ISBAbs ReadAdrAbs
IncSbc 6
ISBAbsX ReadAdrAbsX
IncSbc 7
ISBAbsY ReadAdrAbsY
IncSbc 7
ISBIndX ReadAdrIndX
IncSbc 8
ISBIndY ReadAdrIndY
IncSbc 8
; Komplexe (undokumentierte) Funktionen
ANCImm and.b (RPC)+,RA ;??? ($0b, $2b)
move ccr,RCCR
smi.b RP ;N -> C
Next 2
ASRImm and.b (RPC)+,RA
lsr.b #1,RA
move ccr,RCCR
move.b RCCR,RP
Next 2
ARRImm and.b (RPC)+,RA
lsr.b #1,RP ;Carry -> X
roxr.b #1,RA
move ccr,RCCR
move.b RCCR,RP ;Carry holen
Next 2
ANEImm or.b #$ee,RA
and.b (RPC)+,RA
and.b RX,RA
move ccr,RCCR
Next 2
LXAImm and.b (RPC)+,RA
move.b RA,RX
move ccr,RCCR
Next 2
LASAbsY ReadByteAbsY ;??? ($bb)
and.b RS,d0
move.b d0,RX
move.b d0,RA
move ccr,RCCR
Next 4
SHAAbsY ReadPCWord
move.w d0,d1
lsr.w #8,d1
addq.b #1,d1
and.b RX,d1
and.b RA,d1
add.w RY,d0
WriteByte
Next 5
SHAIndY moveq #0,d0
move.b (RPC)+,d0
move.w (RAMPTR,d0.w),d0 ;(Abgekürzt)
rol.w #8,d0 ;Geht bei ($ff),y schief
move.w d0,d1
lsr.w #8,d1
addq.b #1,d1
and.b RX,d1
and.b RA,d1
add.w RY,d0
WriteByte
Next 6
SHXAbsY ReadPCWord
move.w d0,d1
lsr.w #8,d1
addq.b #1,d1
and.b RY,d1
add.w RY,d0
WriteByte
Next 5
SHYAbsX ReadPCWord
move.w d0,d1
lsr.w #8,d1
addq.b #1,d1
and.b RX,d1
add.w RX,d0
WriteByte
Next 5
SHSAbsY move.b RA,RS
and.b RX,RS
ReadPCWord
move.w d0,d1
lsr.w #8,d1
addq.b #1,d1
and.b RS,d1
WriteByte
Next 5
SBXImm and.b RA,RX
sub.b (RPC)+,RX
move ccr,RCCR
move.b RCCR,RP ;Carry holen und invertieren
not.b RP
Next 2
*
* Erweiterte Opcodes
*
; $d2
OpWrap move.l RPC,d1 ;Wraparound nach $100xx?
sub.l RAMPTR,d1
swap d1
cmp.w #1,d1
bne IllegalOp
sub.l #$10001,RPC ;Ja, zu $00xx umleiten
moveq #0,d1
Next 0
; $f2 $xx
OpIEC move.b (RPC)+,d0 ;Selektor holen
beq OpIECOut
cmp.b #1,d0
beq OpIECOutATN
cmp.b #2,d0
beq OpIECOutSec
cmp.b #3,d0
beq OpIECIn
cmp.b #4,d0
beq OpIECSetATN
cmp.b #5,d0
beq OpIECRelATN
cmp.b #6,d0
beq OpIECTurnaround
cmp.b #7,d0
beq OpIECRelease
bra IllegalOp
OpIECOut move.b $95(RAMPTR),d0 ;Auszugebendes Byte holen
move.b $a3(RAMPTR),d1 ;EOI-Flag holen
bsr IECOut
bra IECSetST
OpIECOutATN move.b $95(RAMPTR),d0 ;Auszugebendes Byte holen
bsr IECOutATN
bra IECSetST
OpIECOutSec move.b $95(RAMPTR),d0 ;Auszugebendes Byte holen
bsr IECOutSec
bra IECSetST
OpIECIn bsr IECIn
move.b d1,RA ;Byte in den Akku
move ccr,RCCR ;Flags entsprechend setzen
bra IECSetST
OpIECSetATN bsr IECSetATN
moveq #0,d0 ;MSWs von d0 und d1 löschen
moveq #0,d1
move.w #$edfb,d0 ;Nach $edfb springen
Jump
Next 0
OpIECRelATN bsr IECRelATN
bra IECReturn
OpIECTurnaround bsr IECTurnaround
bra IECReturn
OpIECRelease bsr IECRelease
bra IECReturn
IECSetST or.b d0,$90(RAMPTR) ;Status setzen
clr.b RP ;Carry löschen
IECReturn moveq #0,d0 ;MSWs von d0 und d1 löschen
moveq #0,d1
bra RTSImpl ;RTS ausführen
**
** Konstanten
**
; Strings
CPUTaskName dc.b "6510",0
TimerIntName dc.b "Frodo Timer Int",0
IDString dc.b "FRODO V1.5",13
dc.b "(C)1994-1995 CHRISTIAN BAUER",0
ds.b 64 ;Muß mind. 92 Zeichen lang sein
CNOP 0,4
*
* Speicherkonfigurationstabelle
*
; Diese Tabelle enthält für alle 8 Speicherkonfigurationen
; die Zeiger auf die zugehörigen Read- und WriteTabs
CNOP 0,4
ConfigTab dc.l ReadTab0,WriteTab0
dc.l ReadTab1,WriteTab1
dc.l ReadTab2,WriteTab2
dc.l ReadTab3,WriteTab3
dc.l ReadTab4,WriteTab4
dc.l ReadTab5,WriteTab5
dc.l ReadTab6,WriteTab6
dc.l ReadTab7,WriteTab7
*
* Opcode Dispatch Table
* "*" bezeichnet einen undokumentierten Opcode
*
CNOP 0,4
OpcodeTable
CyclesLeft dc.w 0 ;Anzahl zur Verfügung stehender CPU-Zyklen
; bis zum nächsten Periodic
dc.w 0
dc.l BRK ;$00
dc.l ORAIndX
dc.l IllegalOp
dc.l SLOIndX ;*
dc.l NOPZero ;*
dc.l ORAZero
dc.l ASLZero
dc.l SLOZero ;*
dc.l PHP ;$08
dc.l ORAImm
dc.l ASLA
dc.l ANCImm ;*
dc.l NOPAbs ;*
dc.l ORAAbs
dc.l ASLAbs
dc.l SLOAbs ;*
dc.l BPLRel ;$10
dc.l ORAIndY
dc.l IllegalOp
dc.l SLOIndY ;*
dc.l NOPZeroX ;*
dc.l ORAZeroX
dc.l ASLZeroX
dc.l SLOZeroX ;*
dc.l CLC ;$18
dc.l ORAAbsY
dc.l NOPImpl ;*
dc.l SLOAbsY ;*
dc.l NOPAbsX ;*
dc.l ORAAbsX
dc.l ASLAbsX
dc.l SLOAbsX
dc.l JSRAbs ;$20
dc.l ANDIndX
dc.l IllegalOp
dc.l RLAIndX ;*
dc.l BITZero
dc.l ANDZero
dc.l ROLZero
dc.l RLAZero ;*
dc.l PLP ;$28
dc.l ANDImm
dc.l ROLA
dc.l ANCImm ;*
dc.l BITAbs
dc.l ANDAbs
dc.l ROLAbs
dc.l RLAAbs ;*
dc.l BMIRel ;$30
dc.l ANDIndY
dc.l IllegalOp
dc.l RLAIndY ;*
dc.l NOPZeroX ;*
dc.l ANDZeroX
dc.l ROLZeroX
dc.l RLAZeroX ;*
dc.l SEC ;$38
dc.l ANDAbsY
dc.l NOPImpl ;*
dc.l RLAAbsY ;*
dc.l NOPAbsX ;*
dc.l ANDAbsX
dc.l ROLAbsX
dc.l RLAAbsX ;*
dc.l RTIImpl ;$40
dc.l EORIndX
dc.l IllegalOp
dc.l SREIndX ;*
dc.l NOPZero ;*
dc.l EORZero
dc.l LSRZero
dc.l SREZero ;*
dc.l PHA ;$48
dc.l EORImm
dc.l LSRA
dc.l ASRImm ;*
dc.l JMPAbs
dc.l EORAbs
dc.l LSRAbs
dc.l SREAbs ;*
dc.l BVCRel ;$50
dc.l EORIndY
dc.l IllegalOp
dc.l SREIndY ;*
dc.l NOPZeroX ;*
dc.l EORZeroX
dc.l LSRZeroX
dc.l SREZeroX ;*
dc.l CLI ;$58
dc.l EORAbsY
dc.l NOPImpl ;*
dc.l SREAbsY ;*
dc.l NOPAbsX ;*
dc.l EORAbsX
dc.l LSRAbsX
dc.l SREAbsX ;*
dc.l RTSImpl ;$60
dc.l ADCIndX
dc.l IllegalOp
dc.l RRAIndX ;*
dc.l NOPZero ;*
dc.l ADCZero
dc.l RORZero
dc.l RRAZero ;*
dc.l PLA ;$68
dc.l ADCImm
dc.l RORA
dc.l ARRImm ;*
dc.l JMPInd
dc.l ADCAbs
dc.l RORAbs
dc.l RRAAbs ;*
dc.l BVSRel ;$70
dc.l ADCIndY
dc.l IllegalOp
dc.l RRAIndY ;*
dc.l NOPZeroX ;*
dc.l ADCZeroX
dc.l RORZeroX
dc.l RRAZeroX ;*
dc.l SEI ;$78
dc.l ADCAbsY
dc.l NOPImpl ;*
dc.l RRAAbsY ;*
dc.l NOPAbsX ;*
dc.l ADCAbsX
dc.l RORAbsX
dc.l RRAAbsX ;*
dc.l NOPZero ;* $80
dc.l STAIndX
dc.l NOPZero ;*
dc.l SAXIndX ;*
dc.l STYZero
dc.l STAZero
dc.l STXZero
dc.l SAXZero ;*
dc.l DEY ;$88
dc.l NOPZero ;*
dc.l TXA
dc.l ANEImm ;*
dc.l STYAbs
dc.l STAAbs
dc.l STXAbs
dc.l SAXAbs ;*
dc.l BCCRel ;$90
dc.l STAIndY
dc.l IllegalOp
dc.l SHAIndY ;*
dc.l STYZeroX
dc.l STAZeroX
dc.l STXZeroY
dc.l SAXZeroY ;*
dc.l TYA ;$98
dc.l STAAbsY
dc.l TXS
dc.l SHSAbsY ;*
dc.l SHYAbsX ;*
dc.l STAAbsX
dc.l SHXAbsY ;*
dc.l SHAAbsY ;*
dc.l LDYImm ;$a0
dc.l LDAIndX
dc.l LDXImm
dc.l LAXIndX ;*
dc.l LDYZero
dc.l LDAZero
dc.l LDXZero
dc.l LAXZero ;*
dc.l TAY ;$a8
dc.l LDAImm
dc.l TAX
dc.l LXAImm ;*
dc.l LDYAbs
dc.l LDAAbs
dc.l LDXAbs
dc.l LAXAbs ;*
dc.l BCSRel ;$b0
dc.l LDAIndY
dc.l IllegalOp
dc.l LAXIndY ;*
dc.l LDYZeroX
dc.l LDAZeroX
dc.l LDXZeroY
dc.l LAXZeroY ;*
dc.l CLV ;$b8
dc.l LDAAbsY
dc.l TSX
dc.l LASAbsY ;*
dc.l LDYAbsX
dc.l LDAAbsX
dc.l LDXAbsY
dc.l LAXAbsY ;*
dc.l CPYImm ;$c0
dc.l CMPIndX
dc.l NOPZero ;*
dc.l DCPIndX ;*
dc.l CPYZero
dc.l CMPZero
dc.l DECZero
dc.l DCPZero ;*
dc.l INY ;$c8
dc.l CMPImm
dc.l DEX
dc.l SBXImm ;*
dc.l CPYAbs
dc.l CMPAbs
dc.l DECAbs
dc.l DCPAbs ;*
dc.l BNERel ;$d0
dc.l CMPIndY
dc.l OpWrap
dc.l DCPIndY ;*
dc.l NOPZeroX ;*
dc.l CMPZeroX
dc.l DECZeroX
dc.l DCPZeroX ;*
dc.l CLD ;$d8
dc.l CMPAbsY
dc.l NOPImpl ;*
dc.l DCPAbsY ;*
dc.l NOPAbsX ;*
dc.l CMPAbsX
dc.l DECAbsX
dc.l DCPAbsX ;*
dc.l CPXImm ;$e0
dc.l SBCIndX
dc.l NOPZero ;*
dc.l ISBIndX ;*
dc.l CPXZero
dc.l SBCZero
dc.l INCZero
dc.l ISBZero ;*
dc.l INX ;$e8
dc.l SBCImm
dc.l NOPImpl
dc.l SBCImm ;*
dc.l CPXAbs
dc.l SBCAbs
dc.l INCAbs
dc.l ISBAbs ;*
dc.l BEQRel ;$f0
dc.l SBCIndY
dc.l OpIEC ;Patch
dc.l ISBIndY ;*
dc.l NOPZeroX ;*
dc.l SBCZeroX
dc.l INCZeroX
dc.l ISBZeroX ;*
dc.l SED ;$f8
dc.l SBCAbsY
dc.l NOPImpl ;*
dc.l ISBAbsY ;*
dc.l NOPAbsX ;*
dc.l SBCAbsX
dc.l INCAbsX
dc.l ISBAbsX ;*
**
** Datenbereich
**
; 6510-Task
CPUProc dc.l 0 ;Prozess-Handle
CPUTask dc.l 0 ;Task des Prozesses
ReadySet dc.l 0 ;Signal des Hauptprogramms
ContinueSet dc.l 0 ;Signal des CPU-Tasks
ReadySig dc.b 0
ContinueSig dc.b 0
; Emulator-Kennung
DFFFByte dc.b $55 ;Wechselt bei jedem Lesen zwischen $55 und $aa
; Interrupt-Flags. Bei einem Interrupt wird eins dieser Flags gesetzt.
; Das bewirkt, daß nach dem nächsten Periodic der 6510-Task in die
; Routine "HandleInt" springt. Dort werden diese Flags ausgewertet und
; entsprechend verzweigt.
CNOP 0,4
Interrupt ;Zusammenfassung als Langwort
IntIsRESET dc.b 0 ;RESET aufgetreten, 6510 beenden oder Pause
IntIsNMI dc.b 0 ;NMI aufgetreten
IntIsIRQ ;Zusammenfassung als Wort
IntIsVICIRQ dc.b 0 ;IRQ durch VIC aufgetreten
IntIsCIAIRQ dc.b 0 ;IRQ durch CIA-A aufgetreten
RESETIsEXIT dc.b 0 ;Zur Unterscheidung von RESET und EXIT
RESETIsPause dc.b 0 ;Zur Unterscheidung von RESET und Pause
CNOP 0,4
RegStore ds.l 6
; Speicherzeiger (außer bei TheChar stimmt bei allen das untere Wort
; mit der tatsächlichen C64-Adresse überein, also
; TheRAM : xxxx0000
; TheBasic : xxxxa000
; TheKernal: xxxxe000
; TheColor : xxxxd800
CNOP 0,4
TheRAM dc.l 0 ;Zeiger auf C64-RAM (64K)
TheBasic dc.l 0 ;Zeiger auf Basic-ROM
TheKernal dc.l 0 ;Zeiger auf Kernal-ROM
TheChar dc.l 0 ;Zeiger auf Char-ROM
TheColor dc.l 0 ;Zeiger auf Farb-RAM
; Taglist für CreateNewProc
ProcTags dc.l NP_Entry,CPUTaskProc
dc.l NP_Name,CPUTaskName
dc.l NP_Priority,-1
dc.l 0,0
; Requester
IllegalOpReq dc.l 20,0,0,0,0
JumpToIOReq dc.l 20,0,0,0,0
RequestStream ds.l 16 ;Argumente
SECTION "BSS",BSS
; Sprungtabellen für Speicherzugriff: Ein Eintrag pro Seite
; Eine Tabelle für jede der 8 Speicherkonfigurationen
ReadTab0 ds.l 256
ReadTab1 ds.l 256
ReadTab2 ds.l 256
ReadTab3 ds.l 256
ReadTab4 ds.l 256
ReadTab5 ds.l 256
ReadTab6 ds.l 256
ReadTab7 ds.l 256
WriteTab0 ds.l 256
WriteTab1 ds.l 256
WriteTab2 ds.l 256
WriteTab3 ds.l 256
WriteTab4 ds.l 256
WriteTab5 ds.l 256
WriteTab6 ds.l 256
WriteTab7 ds.l 256
JumpTab0 ds.l 256
JumpTab1 ds.l 256
JumpTab2 ds.l 256
JumpTab3 ds.l 256
JumpTab4 ds.l 256
JumpTab5 ds.l 256
JumpTab6 ds.l 256
JumpTab7 ds.l 256
END